<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <title>Title</title>
    
    <style>
      .carousel-container {
        border: 1px gray solid;
        border-radius: 10px;
        padding: 15px;
        display: grid;
        grid-template-columns: repeat(2, 1fr);
        column-gap: 15px;
        row-gap: 15px;
        width: 400px;
        height: 320px;
        overflow-y: auto;
      }
      
      .carousel-container::-webkit-scrollbar { /* 滚动条整体样式 */
        width: 4px;
        background-color: transparent;
      }
      
      .carousel-container::-webkit-scrollbar-thumb { /* 滚动条里面小方块 */
        width: 4px;
        background: #7D7E7D;
        border-radius: 2px;
      }
      
      .carousel-container-son {
        height: 90px;
        background: darkgray;
        color: white;
        display: flex;
        justify-content: center;
        align-items: center;
        font-size: 25px;
        scroll-margin: 15px;
      }
      
      @keyframes slide-top {
        from {
          transform: translateY(0);
        }
        to {
          transform: translateY(-105px);
        }
      }
      
      .item-move {
        -webkit-animation: slide-top 0.5s cubic-bezier(0.25, 0.46, 0.45, 0.94) both;
        animation: slide-top 0.5s cubic-bezier(0.25, 0.46, 0.45, 0.94) both;
      }
    </style>
  
  </head>
  
  <body>
    <!--
       1.为滚动容器设置宽度或高度、X或Y轴滚动条
       2.CSS样式item-move为滚动子元素添加消失动画，其中to的translateY设置轮播距离，该距离根据实际轮播需要设置
       3.创建定时器，具体逻辑看代码
       4.鼠标移入onmouseenter和移出onmouseleave时，分别暂停和开始轮询
       5.此方法无需关注手动移动滚动条的问题
     -->
    <div
      class="carousel-container"
      onmouseenter="endCarrouselInterval()"
      onmouseleave="startCarrouselInterval()"
    >
      <div class="carousel-container-son">1</div>
      <div class="carousel-container-son">2</div>
      <div class="carousel-container-son">3</div>
      <div class="carousel-container-son">4</div>
      <div class="carousel-container-son">5</div>
      <div class="carousel-container-son">6</div>
      
      <div class="carousel-container-son">7</div>
      <div class="carousel-container-son">8</div>
      <div class="carousel-container-son">9</div>
      <div class="carousel-container-son">10</div>
      <div class="carousel-container-son">11</div>
      <div class="carousel-container-son">12</div>
      
      <div class="carousel-container-son">13</div>
      <div class="carousel-container-son">14</div>
      <div class="carousel-container-son">15</div>
      <div class="carousel-container-son">16</div>
      <div class="carousel-container-son">17</div>
      <div class="carousel-container-son">18</div>
      
      <div class="carousel-container-son">19</div>
      <div class="carousel-container-son">20</div>
      <div class="carousel-container-son">21</div>
      <div class="carousel-container-son">22</div>
      <div class="carousel-container-son">23</div>
      <div class="carousel-container-son">24</div>
      
      <div class="carousel-container-son">25</div>
      <div class="carousel-container-son">26</div>
      <div class="carousel-container-son">27</div>
      <div class="carousel-container-son">28</div>
      <div class="carousel-container-son">29</div>
      <div class="carousel-container-son">30</div>
      
      <div class="carousel-container-son">31</div>
      <div class="carousel-container-son">32</div>
      <div class="carousel-container-son">33</div>
    </div>
  </body>
  
  <script>
    let carouselInterval = null;
    
    // 开始轮播
    function startCarrouselInterval() {
      carouselInterval = setInterval(() => {
        // 被轮播掉的首部滚动子元素添加到滚动容器尾部，首部元素个数与轮播距离相关，若子元素存在事件需要通过JS重新添加
        const carouselContainer = document.querySelector('.carousel-container');
        const firstItem = carouselContainer.firstElementChild.cloneNode(true);
        carouselContainer.appendChild(firstItem);
        const secondItem = carouselContainer.firstElementChild.nextElementSibling.cloneNode(true);
        carouselContainer.appendChild(secondItem);
        
        // 为滚动子元素添加消失动画
        const carouselContainerSon = document.querySelectorAll('.carousel-container-son');
        carouselContainerSon.forEach((item) => {
          let className = item.getAttribute('class');
          className += ' item-move';
          item.setAttribute('class', className.trim());
        });
        
        // 等待消失动画执行完毕
        setTimeout(() => {
          // 删除滚动子元素消失动画
          carouselContainerSon.forEach((item) => {
            let className = item.getAttribute('class');
            className = className.replaceAll('item-move', '');
            item.setAttribute('class', className.trim());
          });
          
          // 真正删除被轮播掉的首部滚动子元素
          carouselContainer.removeChild(carouselContainer.firstElementChild);
          carouselContainer.removeChild(carouselContainer.firstElementChild);
        }, 1000);
      }, 4000);
    }
    
    // 结束轮播
    function endCarrouselInterval() {
      clearInterval(carouselInterval);
      carouselInterval = null;
    }
    
    startCarrouselInterval();
  </script>
</html>